package com.jun.admin.core.utils;

import jodd.util.StringUtil;
import lombok.SneakyThrows;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
import org.apache.poi.xwpf.usermodel.XWPFChart;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.List;

/**
 * @author yuejun.li
 * @date 2024/10/16 10:27:28
 * word工具类
 */
@Component
public class WordUtil {

    @Autowired
    private HttpServletResponse response;

    /**
     * 导出单个图表类型（柱状图，折线图，饼图等）的图表
     * @param document 文档对象
     * @param chartTitle 图表标题
     * @param fileName 文件名称
     * @param datas 数据集合
     * @param xValues x轴（类别）
     * @param seriesNames 系列标题
     */
    @SneakyThrows
    public void exportSingleChart(XWPFDocument document, String chartTitle, String fileName, List<Number[]> datas, String[] xValues, String[] seriesNames){
        setHeaders(fileName);

        //获取word中所有图表对象
        List<XWPFChart> charts = document.getCharts();
        //获取第一个单系列柱状图
        XWPFChart docChart = charts.get(0);

        //图表整体的标题 传空值则不替换标题
        if (StringUtil.isNotBlank(chartTitle)) {
            docChart.setTitleText(chartTitle);
            docChart.setTitleOverlay(false);
        }

        //获取图表数据对象（xlsx的图表对象）
        //图表里的图类型数量（比如折线+柱形的组合图则 getChartSeries.size = 2）
        //还有区域图、柱状图、饼图、雷达图等...
        XDDFChartData chartData = docChart.getChartSeries().get(0);

        //word图表均对应一个内置的excel，用于保存图表对应的数据
        //excel中 第一列第二行开始的数据为分类信息
        //CellRangeAddress(1, categories.size(), 0, 0) 四个参数依次为 起始行 截止行 起始列 截止列。

        //excel中分类信息的范围
        String catDataRange = docChart.formatRange(new CellRangeAddress(1, xValues.length, 0, 0));
        //根据分类信息的范围创建分类信息的数据源（填分类信息）
        XDDFDataSource<?> catDataSource = XDDFDataSourcesFactory.fromArray(xValues, catDataRange, 0);
        //更新数据
        for (int i = 0; i < seriesNames.length; i++) {
            //excel中各系列对应的数据的范围（以列为单位划范围）
            String valDataRange = docChart.formatRange(new CellRangeAddress(1, xValues.length, i + 1, i + 1));
            //根据数据的范围创建值的数据源（填值信息）
            Number[] val = datas.get(i);
            XDDFNumericalDataSource<Number> valDataSource = XDDFDataSourcesFactory.fromArray(val, valDataRange, i + 1);
            //获取图表系列的数据对象
            XDDFChartData.Series series = chartData.getSeries(i);
            //替换系列数据对象中的分类和值
            series.replaceData(catDataSource, valDataSource);
            //修改系列数据对象中的标题（系列的标题名）
            CellReference cellReference = docChart.setSheetTitle(seriesNames[i], i + 1);
            series.setTitle(seriesNames[i], cellReference);
            //更新图表数据对象
            docChart.plot(chartData);
        }
    }

    /**
     * 导出多个图表类型（含柱状图，折线图，饼图等组合图）的图表
     * @param document 文档对象
     * @param chartTitle 图表标题
     * @param fileName 文件名称
     * @param datas 数据集
     * @param xValues x轴（类别）
     * @param seriesNames 系列标题
     */
    @SneakyThrows
    public void exportMultiChart(XWPFDocument document, String chartTitle, String fileName, List<Number[]> datas, String[] xValues, String[][] seriesNames){
        setHeaders(fileName);

        //获取word中所有图表对象
        List<XWPFChart> charts = document.getCharts();
        //获取第一个单系列柱状图
        XWPFChart docChart = charts.get(0);

        if (StringUtil.isNotBlank(chartTitle)) {
            docChart.setTitleText(chartTitle);
            docChart.setTitleOverlay(false);
        }

        //获取图表数据对象
        XDDFChartData chartData = null;

        //word图表均对应一个内置的excel，用于保存图表对应的数据
        //excel中 第一列第二行开始的数据为分类信息
        //CellRangeAddress(1, categories.size(), 0, 0) 四个参数依次为 起始行 截止行 起始列 截止列。

        //excel中分类信息的范围
        String catDataRange = docChart.formatRange(new CellRangeAddress(1, xValues.length, 0, 0));
        //根据分类信息的范围创建分类信息的数据源
        XDDFDataSource<?> catDataSource = XDDFDataSourcesFactory.fromArray(xValues, catDataRange, 0);
        //更新数据
        int indexCount = 0;
        //外循环 因有2种类型的图标（柱形+折线），所以循环次数为2
        for (int i = 0; i < seriesNames.length; i++) {
            chartData = docChart.getChartSeries().get(i);
            for (int j = 0; j < seriesNames[i].length; j++) {
                //excel中各系列对应的数据的范围
                String valDataRange = docChart.formatRange(new CellRangeAddress(1, xValues.length, indexCount + 1, indexCount + 1));
                //根据数据的范围创建值的数据源
                Number[] val = datas.get(indexCount);
                XDDFNumericalDataSource<Number> valDataSource = XDDFDataSourcesFactory.fromArray(val, valDataRange, indexCount + 1);
                //获取图表系列的数据对象(第一个chartData为柱形图，第二个chartData为折线图，然后再获取图中的系列对象)
                XDDFChartData.Series series = chartData.getSeries(j);
                //替换系列数据对象中的分类和值
                series.replaceData(catDataSource, valDataSource);
                //修改系列数据对象中的标题
                CellReference cellReference = docChart.setSheetTitle(seriesNames[i][j], indexCount + 1);
                series.setTitle(seriesNames[i][j], cellReference);
                //更新图表数据对象
                docChart.plot(chartData);
                indexCount++;
            }
        }
    }



    // 设置响应内容类型和头部
    public void setHeaders(String fileName) throws UnsupportedEncodingException {
        response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName + ".docx", "UTF-8"));
    }
}
